package cz.vse.adventura.po1715.xburj54_bursa.hra;

import cz.pecinovsky.english.pojj.adv_framework.game_txt.INamed;
import cz.pecinovsky.english.pojj.adv_framework.game_txt.ICommand;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;


/*******************************************************************************
 * Instance třídy {@code APříkaz} obsahuje kolekci všech příkazů,
 * které je možné ve hře zadat.
 * Třída {@code APříkaz} je rodičovskou třídou všech přikazů.
 *
 * @author Jan Bursa
 * @version 1.02,  16.12.2010
 */
abstract class APříkaz implements ICommand
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    private static final String UVÍTÁNÍ =
             "Vítejte ve hře. Projděte celým domem a odneste si ten nejcennější suvenýr" +
          "\n Najděte v bytě trezor. Zde se vždy nachází nějaká cennost." +
        "\n\n Nyní se nacházíte na: Zahrada" +
          "\n Můžete se přesunout do: Garáž, Vchod" +
          "\n Na zahradě se nachází: Květiny, Plot";

    private static final String PRÁZDNÝ =
            "Zadal(a) jste prázdný příkaz. "+
            "\n Chcete-li poradit, zadejte příkaz ?";

    private static final String NEZNÁM =
            "Tento příkaz neznám. " +
            "\n Chcete-li poradit, zadejte příkaz ?";

     private static final Map<String, APříkaz> název2příkaz = new HashMap<String, APříkaz>();

     private static final APříkaz
            PŘÍKAZ_HELP = new PříkazHelp(),
            PŘÍKAZ_JDI = new PříkazJdi(),
            PŘÍKAZ_ODSUN = new PříkazOdsuň(),
            PŘÍKAZ_OTEVRI = new PříkazOtevři(),
            PŘÍKAZ_POLOZ = new PříkazPolož(),
            PŘÍKAZ_POUZIJ = new PříkazPoužij(),
            PŘÍKAZ_PROZKOUMEJ = new PříkazProzkoumej(),
            PŘÍKAZ_SUNDEJ = new PříkazSundej(),
            PŘÍKAZ_VEZMI = new PříkazVezmi(),
            PŘÍKAZ_KONEC = new PříkazKonec();

//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================

     /** Příznak toho, je-li hra rozehraná nebo
     *  je-li skončená a bude se startovat nová. */
     private static boolean poprvé = true;

//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

    private final String název;
    private final String popis;

//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================

    /***************************************************************************
     * Vrátí kolekci všech příkazů použitelných ve hře.
     *
     * @return Požadovaná kolekce
     */
   // @Override
    public static Collection<APříkaz> getPříkazy()
     {
        return Collections.unmodifiableCollection(název2příkaz.values());
     }

    /***************************************************************************
     * Vrací název příkazu, tj. text, který musí hráč zadat
     * pro vyvolaní daného příkazu.
     *
     * @return Název příkazu
     */
    @Override
    public String getName()
     {
        return název;
     }

    /***************************************************************************
     * Vrací popis příkazu s vysvětlením jeho funkce
     * a významu jednotlivých parametru.
     *
     * @return Popis příkazu
     */
    @Override
    public String getDescription()
     {
        return popis;
     }

        /***************************************************************************
     * Vrátí informaci o tom, jeli hra již skočena a lze-li proto začít novou.
     * @return
     */
    static boolean isSkončeno()
    {
        return poprvé;
    }

//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================
    
    /***************************************************************************
     * Zpracuje zadaný příkaz a vrátí text zprávy pro uživatele.
     *
     * @param příkaz Zadávaný příkaz
     * @return Textová odpověď hry na zadaný příkaz
     */
  //  @Override
        static String zpracujPříkaz(String příkaz)
    {
        příkaz = příkaz.trim().toLowerCase();
        if (poprvé) {
            return start(příkaz);
        }
        if (příkaz.equals("")) {
            return PRÁZDNÝ;
        }
        String[] slova = příkaz.split("\\s+");
        ICommand  akce = název2příkaz.get(slova[0]);
        if (akce == null) {
            return NEZNÁM;                                  //==========>
        }
        String[] parametry = new String[slova.length-1];
        System.arraycopy(slova, 1, parametry, 0, parametry.length);

        String  odpověď = akce.execute(parametry);
        odpověď = doplň(odpověď);
        return  odpověď;
    }

     /***************************************************************************
     * Oznámení o ukončení hry.
     * Příští volání metody {@link #zpracujPříkaz(String)}
     * bude opět prvním voláním v nové hře.
     */
    public static void konec() {
        poprvé = true;
    }

   /***************************************************************************
     * Metoda realizující reakci hry na zadaní daného příkazu.
     * Počet parametrů je závislý na konkrétním příkazu, např. příkazy konec
     * a nápověda nemají parametry, příkazy jdi a seber maji jeden parametr
     * příkaz použij muže mít dva parametry atd.
     *
     * @param parametry Parametry příkazu;
     *                  jejich počet muže byt pro každý příkaz jiný
     * @return Text zprávy vypsané po provedeni příkazu
     */
   @Override
    public abstract String execute( String... parametry );

//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================
    /***************************************************************************
     * Vytvoří nový příkaz se zadaným názvem a popisem své funkce.
     *
     * @param název Název vytvářeného příkazu
     * @param popis Stručný popis funkce, použití a účelu příkazu
     */
    public APříkaz(String název, String popis) {
        this.název = název;
        this.popis = popis;
        název2příkaz.put(název.toLowerCase(), this);
    }


//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================
//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================

     /***************************************************************************
     * Vrátí název dané instance.
     *
     * @return Nazev instance
     */
    @Override
    public String toString()
    {
        return název;
    }

//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
    
     /***************************************************************************
     * Vrátí text s informacemi o aktuálním stavu hry.
     * @return Požadovaný informační text
     */
    private static String doplň(String  odpověď)
    {
        StringBuilder sb = new StringBuilder(odpověď);
        Collection<INamed> kolekce;

        Místnost am = Místnost.getAktuálníMístnost();
        připoj(sb, "Sousedé:  ", am.getNeighbors());
        připoj(sb, "Předměty: ", am.getObjects());
        připoj(sb, "Kapsy:    ", Kapsa.getKapsa().getObjects());

        return sb.toString();
    }

    /***************************************************************************
     * Do zadaného stringbuilderu přidá zadaný titulek
     * následovaný vyjmenovanými položkami ze zadané kolekce.
     *
     * @param sb       Doplňovaný StringBuilder
     * @param titulek  Přidávaný titulek
     * @param objekty  Kolekce přidávaných objektů
     */
    private static void připoj(StringBuilder sb, String titulek,
                        Collection<? extends INamed> objekty)
    {
        sb.append('\n').append(titulek).append(objekty);
    }

     /***************************************************************************
     * Odstartuje novou hru.
     */
    private static String start(String příkaz)
    {
        if (příkaz.equals("")) {
            Místnost.inicializuj();
            Kapsa.inicializuj();
            poprvé = false;
            return UVÍTÁNÍ;                             //==========>
        } else {
            throw new IllegalStateException(
                                "Prvním příkazem není bezejmenný příkaz.");
        }
    }
           
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTOVACÍ METODY A TŘÍDY ==================================================
//
//     /***************************************************************************
//      * Testovací metoda.
//      */
//     public static void test()
//     {
//         APříkaz x = new APříkaz();
//     }
//     /** @param args Parametry příkazového řádku - nepoužívané. */
//     public static void main(String[] args)  {  test();  }
}
